package mongox

import (
	"fmt"
	"gitee.com/zhongguo168a/go-nodex/dbx"
	"gitee.com/zhongguo168a/go-nodex/logx"
	"gitee.com/zhongguo168a/gocodes/datax/coderx"
	"gitee.com/zhongguo168a/gocodes/datax/jsonmap"
	"gitee.com/zhongguo168a/gocodes/myx/errorx"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func (req *Request) CreateIndexs(query *mongo.IndexModel, opts ...*options.CreateIndexesOptions) (err error) {
	col, err := req.GetCollection()
	if err != nil {
		return
	}

	logx.Debug(fmt.Sprintf("[DB] CREATE_INDEXES FROM %v.%v INDEX=%v OPTS=%v", req.table.Database, req.table.Name, query, opts))
	_, err = col.Indexes().CreateOne(req.getContext(), *query, opts...)
	if err != nil {
		return
	}

	return
}

func (req *Request) DeleteOne(query bson.M, opts ...*options.DeleteOptions) (err error) {
	col, err := req.GetCollection()
	if err != nil {
		return
	}
	//
	logx.Debug(fmt.Sprintf("[DB] DELETE FROM %v.%v: %v", req.table.Database, req.table.Name, query))
	_, err = col.DeleteOne(req.getContext(), query, opts...)
	if err != nil {
		return
	}

	return
}
func (req *Request) DeleteMany(query bson.M, opts ...*options.DeleteOptions) (err error) {
	col, err := req.GetCollection()
	if err != nil {
		return
	}
	//
	logx.Debug(fmt.Sprintf("[DB] DELETE FROM %v.%v: %v", req.table.Database, req.table.Name, query))
	_, err = col.DeleteMany(req.getContext(), query, opts...)
	if err != nil {
		return
	}

	return
}

func (req *Request) InsertOne(document interface{}, opts ...*options.InsertOneOptions) (err error) {
	col, err := req.GetCollection()
	if err != nil {
		return
	}
	if document == nil {
		err = errorx.New("document is nil")
		return
	}
	document, err = coderx.AnyToMap(document)
	if err != nil {
		return
	}
	//
	logx.Debug(fmt.Sprintf("[DB] INSERT FROM %v.%v, DOCUMENT=%v ", req.table.Database, req.table.Name, document))
	_, err = col.InsertOne(req.getContext(), document, opts...)
	if err != nil {
		return
	}

	return
}

func (req *Request) InsertMany(documents []interface{}, opts ...*options.InsertManyOptions) (result *mongo.InsertManyResult, err error) {
	col, err := req.GetCollection()

	//newDocuments := make([]interface{}, len(documents), cap(documents))
	//for i := 0; i < len(documents); i++ {
	//	document, anyerr := coderx.AnyToMap(documents[i])
	//	if anyerr != nil {
	//		err = errorx.Wrap(anyerr, "any to map", datax.M{"index": i})
	//		return
	//	}
	//
	//	newDocuments[i] = document
	//}
	newDocuments := documents
	//
	logx.Debug(fmt.Sprintf("[DB] INSERT FROM %v.%v, DOCUMENT=%v ", req.table.Database, req.table.Name, newDocuments))
	result, err = col.InsertMany(req.getContext(), newDocuments, opts...)
	if err != nil {
		return
	}

	return
}

func (req *Request) UpdateOne(filter bson.M, update map[string]interface{}, opts ...*options.UpdateOptions) (result *mongo.UpdateResult, err error) {
	col, err := req.GetCollection()
	if err != nil {
		return
	}
	if update == nil {
		err = errorx.New("update is nil")
		return
	}
	//opts = options.Update().SetUpsert(true)
	logx.Debug(fmt.Sprintf("[DB] UPDATE FROM %v.%v FILTER=%v UPDATE=%v", req.table.Database, req.table.Name, filter, update))
	result, err = col.UpdateOne(req.getContext(), filter, update, opts...)
	if err != nil {
		return
	}

	return
}

func (req *Request) FindOneAndUpdate(query bson.M, update map[string]interface{}, opts ...*options.FindOneAndUpdateOptions) (result interface{}, err error) {
	col, err := req.GetCollection()
	if err != nil {
		return nil, err
	}
	logx.Debug(fmt.Sprintf("[DB] READ FROM %v.%v QUERY=%v", req.table.Database, req.table.Name, query))
	r := col.FindOneAndUpdate(req.getContext(), query, update, opts...)
	if r.Err() != nil {
		rerr := r.Err()
		if rerr.Error() == "mongo: no documents in result" {
			return nil, dbx.ErrNotFound
		} else {
			return nil, rerr
		}
	}
	columns := map[string]interface{}{}
	err = r.Decode(&columns)
	if err != nil {
		return nil, errorx.Wrap(err, "decode")
	}
	pid, ok := columns["_id"].(primitive.ObjectID)
	if ok {
		columns["_id"] = pid.Hex()
	}
	jsonmap.MapToJsonMap(columns, columns)
	if req.itemHandler != nil && req.itemCreator != nil {
		var item = req.itemCreator()
		newitem, itemerr := req.itemHandler(item, columns)
		if itemerr != nil {
			return nil, itemerr
		}
		return newitem, nil
	}
	return columns, nil

}

func (req *Request) BulkWrite(models []mongo.WriteModel, opts ...*options.BulkWriteOptions) (result *mongo.BulkWriteResult, err error) {
	col, err := req.GetCollection()
	if err != nil {
		return
	}
	//
	//opts = options.Update().SetUpsert(true)
	logx.Debug(fmt.Sprintf("[DB] BulkWrite FROM %v.%v MODLES=%v", req.table.Database, req.table.Name, len(models)))
	_, err = col.BulkWrite(req.getContext(), models, opts...)
	if err != nil {
		return
	}

	return
}
